package com.springcloud.jwt;

import com.springcloud.commons.utils.StringUtils;
import com.springcloud.model.SysResource;
import com.springcloud.security.MyFailureHandler;
import com.springcloud.service.ISysResourceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * JWT验证过滤器，放在用户密码过滤器之前 解析token中用户信息，并赋予上下文
 * 也就是说,所有的认证逻辑可以放在这里
 * @author Administrator
 *
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Autowired
    private JwtConfigProperty jwtConfig;
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    MyFailureHandler myFailureHandler;
    @Autowired
    ISysResourceService resourceService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Value("${jwt.expirationMinute}")
    String expirationMinute;


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        String authHeader = "";
        Cookie[] cookies = request.getCookies();
        if (cookies!=null) {
            for (int i = 0; i < cookies.length; i++) {
                Cookie cookie = cookies[i];
                if (cookie.getName().equals(jwtConfig.getHeader())) {
                    authHeader = cookie.getValue();
                    break;
                }
            }
        }
        if(StringUtils.isBlank(authHeader)) {
            authHeader = request.getHeader(jwtConfig.getHeader());//获取浏览器传过来的token信息
        }
        String tokenHead = jwtConfig.getTokenHead(); //获取配置文件的token开头
        if (StringUtils.isNotBlank(authHeader) && authHeader.startsWith(tokenHead)) { //验证token是否为空,验证是否为配置文件的开头
            String authToken = authHeader.substring(tokenHead.length());//去掉开头
            try {
                if (jwtUtil.validateToken(authToken)) { //验证token是否合法
                    String uri = request.getRequestURI(); // 获取uri
                    String userid = jwtUtil.getSubjectFromToken(authToken); // 获取userid

                    String uris = (String) stringRedisTemplate.opsForValue().get(userid);
                    boolean b = false;
                    if(StringUtils.isNotBlank(uris)){
                    String[] uriarr = uris.split(",");
                        for(String i:uriarr){
                            if(uri.equals(i)){
                                b = true ;
                                break;
                            }
                        }
                    }
                    if(b) {
                        //如果有认证逻辑,或者是延长token时间可以写到这里
                        String token = jwtUtil.generateToken(userid);
                        response.setHeader(jwtConfig.getHeader(), tokenHead + token);//这里比较邪恶,每次访问都返回一个新的token
                        stringRedisTemplate.opsForValue().set(userid,uris,Long.valueOf(expirationMinute)+1,TimeUnit.MINUTES);
//                        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
//                        authorities.add(new SimpleGrantedAuthority("1"));
                        //这里的信息其实是可以随便填写的,因为要创建下面的SecurityContextHolder,
                        //这个本来是存session信息的，我们用jwt实现就无所谓了
                        // 由于这个SecurityContextHolder每次连接后都会清除掉,所以也不占什么资源
                        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
                        logger.info("jwt+++++++++++++++++"+Thread.currentThread().getName());
                        authorities.add(new SimpleGrantedAuthority(userid));
                        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                                userid, null, authorities);
                        SecurityContextHolder.getContext().setAuthentication(authentication);
                    }
                }
            }catch (Exception e) {
                logger.info("token格式有误");
            }
        }
        filterChain.doFilter(request, response);

    }

}
